/*
 * Copyright (C) 2010 Fred Barrie This program is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version. This program is distributed
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received
 * a copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package org.aergia.vinny.gui.view;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.PrinterException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.aergia.vinny.database.pojo.VinnyRole;
import org.aergia.vinny.database.pojo.VinnyUser;
import org.aergia.vinny.gui.controller.VinnyController;
import org.aergia.vinny.gui.util.DialogUtil;
import org.aergia.vinny.util.IconUtil;

public class UserFrame extends JFrame implements ActionListener, ChangeListener {

	abstract class UserFramePanel extends JPanel {

		private static final long serialVersionUID = 1L;

		/**
		 * @param listener
		 */
		protected void setActionListener(final ActionListener listener) {
			// null;
		}
	}

	private static Logger logger = Logger.getLogger("UserFrame");

	private static final long serialVersionUID = 1L;
	JButton approveAllButton;
	private JButton configurationButton;
	private JTabbedPane configurationPane;
	private final VinnyController controller;
	private volatile DatabasePojoPanel currentPanel;
	private final Map<String, JTabbedPane> map;
	private JPanel panes;
	private JButton printButton;
	private JButton serviceButton;
	private JTabbedPane servicePane;
	private final VinnyUser user;
	private JButton userButton;
	private JTabbedPane userPane;
	private JButton volunteerButton;

	private JTabbedPane volunteerPane;

	/**
	 * @param controller
	 * @param user
	 */
	public UserFrame(final VinnyController controller, final VinnyUser user) {
		UserFrame.logger = Logger.getLogger(UserFrame.class.getName());
		this.map = new HashMap<String, JTabbedPane>();
		this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
		this.controller = controller;
		this.user = user;
		this.initComponents();
		this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
		this.refreshPanels(this.volunteerPane.getComponents());
	}

	@Override
	public void actionPerformed(final ActionEvent e) {
		if (e.getSource() instanceof JButton) {
			final String name = ((JButton) e.getSource()).getName();

			final JTabbedPane pane = this.map.get(name);
			final Component c = pane.getSelectedComponent();
			if (c != null) {
				this.currentPanel = (DatabasePojoPanel) c;
			}
			this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
			this.refreshPanels(this.map.get(name).getComponents());
			this.showPane(name);
			this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
		}
	}

	@Override
	public void stateChanged(final ChangeEvent e) {
		if (e.getSource() instanceof JTabbedPane) {
			final JTabbedPane pane = (JTabbedPane) e.getSource();
			this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
			this.refreshPanels(pane.getComponents());
			this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
			final Component c = pane.getSelectedComponent();
			if (c != null) {
				this.currentPanel = (DatabasePojoPanel) pane.getSelectedComponent();
			}
		}
	}

	protected void printButtonActionPerformed() {
		try {
			if (this.currentPanel != null) {
				this.currentPanel.printTable();
			}
		} catch (final PrinterException e) {
			DialogUtil.alert(this, e.getMessage(), "Print Error");
		}
	}

	private UserFramePanel createServiceAdditionalPanel() {
		final UserFramePanel panel = new UserFramePanel() {
			private static final long serialVersionUID = 1L;

			@Override
			protected void setActionListener(final ActionListener listener) {
				UserFrame.this.approveAllButton.addActionListener(listener);
			}
		};
		panel.add(this.approveAllButton);
		return panel;
	}

	private JButton getConfigurationButton() {
		if (this.configurationButton == null) {
			this.configurationButton = new JButton();
			this.configurationButton.setText("");
			this.configurationButton.setName(VinnyRole.MODIFY_CONFIGURATION);
			this.configurationButton.setToolTipText("Configuration options");
			this.configurationButton.setIcon(IconUtil.getIcon("/images/32/settings.png"));
			this.configurationButton.addActionListener(this);
		}
		return this.configurationButton;
	}

	private JButton getPrintButton() {
		if (this.printButton == null) {
			this.printButton = new JButton();
			this.printButton.setToolTipText("Print Reports");
			this.printButton.setIcon(IconUtil.getIcon("/images/32/print.png"));
			this.printButton.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(final ActionEvent e) {
					UserFrame.this.printButtonActionPerformed();
				}
			});
		}
		return this.printButton;
	}

	private JButton getServiceButton() {
		if (this.serviceButton == null) {
			this.serviceButton = new JButton();
			this.serviceButton.setName(VinnyRole.MODIFY_SERVICE);
			this.serviceButton.setText("");
			this.serviceButton.setToolTipText("Service options");
			this.serviceButton.setIcon(IconUtil.getIcon("/images/32/service.png"));
			this.serviceButton.addActionListener(this);
		}
		return this.serviceButton;
	}

	private JButton getUserButton() {
		if (this.userButton == null) {
			this.userButton = new JButton();
			this.userButton.setName(VinnyRole.MODIFY_USER);
			this.userButton.setText("");
			this.userButton.setToolTipText("User options");
			this.userButton.setIcon(IconUtil.getIcon("/images/32/security.png"));
			this.userButton.addActionListener(this);
		}
		return this.userButton;
	}

	private JButton getVolunteerButton() {
		if (this.volunteerButton == null) {
			this.volunteerButton = new JButton();
			this.volunteerButton.setName(VinnyRole.MODIFY_VOLUNTEER);
			this.volunteerButton.setText("");
			this.volunteerButton.setToolTipText("Volunteer options");
			this.volunteerButton.setIcon(IconUtil.getIcon("/images/32/user-1.png"));
			this.volunteerButton.addActionListener(this);
		}
		return this.volunteerButton;
	}

	private void initComponents() {
		this.setLayout(new BorderLayout());

		this.approveAllButton = new JButton();
		this.approveAllButton.setIcon(IconUtil.getIcon("/images/32/edit.png"));
		this.approveAllButton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(final ActionEvent e) {
				// empty
			}
		});
		this.approveAllButton.setActionCommand("Approve All");
		this.approveAllButton.setText("Approve");

		final JPanel buttonPanel = new JPanel(new GridLayout(0, 1));
		if (this.user.inRole(VinnyRole.MODIFY_VOLUNTEER)) {
			buttonPanel.add(this.getVolunteerButton());
		}
		if (this.user.inRole(VinnyRole.MODIFY_SERVICE)) {
			buttonPanel.add(this.getServiceButton());
		}
		if (this.user.inRole(VinnyRole.MODIFY_CONFIGURATION)) {
			buttonPanel.add(this.getConfigurationButton());
		}
		if (this.user.inRole(VinnyRole.MODIFY_USER)) {
			buttonPanel.add(this.getUserButton());
		}

		for (int i = buttonPanel.getComponentCount(); i < 7; i++) {
			buttonPanel.add(new JLabel());
		}

		buttonPanel.add(this.getPrintButton());
		this.add(buttonPanel, BorderLayout.WEST);

		this.servicePane = new JTabbedPane();
		this.servicePane.addTab("Hours", new ServicePanel(this.controller, this.user, this.createServiceAdditionalPanel()));
		this.servicePane.addTab("Scans", new ScanPanel(this.controller, this.user));
		this.servicePane.addChangeListener(this);

		this.volunteerPane = new JTabbedPane();
		this.volunteerPane.addTab("Volunteers", new VolunteerPanel(this.controller, this.user));
		this.volunteerPane.addTab("Card", new CardPanel(this.controller, this.user));
		this.volunteerPane.addTab("Groups", new GroupPanel(this.controller, this.user));
		this.volunteerPane.addChangeListener(this);

		this.configurationPane = new JTabbedPane();
		this.configurationPane.addTab("Options", new OptionPanel(this.controller, this.user));
		this.configurationPane.addTab("Operating Hours", new OperatingHoursPanel(this.controller, this.user));
		this.configurationPane.addTab("Service Types", new ServiceTypePanel(this.controller, this.user));
		this.configurationPane.add("Workstations", new WorkstationPanel(this.controller, this.user));
		this.configurationPane.addChangeListener(this);

		this.userPane = new JTabbedPane();
		this.userPane.addTab("Users", new UserPanel(this.controller, this.user));
		this.userPane.addChangeListener(this);

		this.map.put(VinnyRole.MODIFY_CONFIGURATION, this.configurationPane);
		this.map.put(VinnyRole.MODIFY_SERVICE, this.servicePane);
		this.map.put(VinnyRole.MODIFY_USER, this.userPane);
		this.map.put(VinnyRole.MODIFY_VOLUNTEER, this.volunteerPane);

		this.panes = new JPanel(new CardLayout());
		this.panes.add(new JPanel(), "Introduction");
		for (final String key : this.map.keySet()) {
			this.panes.add(this.map.get(key), key);
		}

		this.add(this.panes, BorderLayout.CENTER);
		this.setSize(1150, 640);
		this.setIconImage(IconUtil.getIconImage("/images/16/trackin_it.png"));
	}

	private void refreshPanels(final Component[] components) {
		for (final Component c : components) {
			if (c instanceof DatabasePanel) {
				((DatabasePanel) c).refresh();
			}
		}
	}

	private void showPane(final String name) {
		final CardLayout cl = (CardLayout) this.panes.getLayout();
		cl.show(this.panes, name);
	}
}
